﻿using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace System.Data.Entity.Extensions.Repository
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    public interface IRepository<TEntity> : IDisposable where TEntity : class
    {
        #region Create

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        TEntity Create();

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TDerivedEntity"></typeparam>
        /// <returns></returns>
        TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, TEntity;
        
        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Created;

        #endregion

        #region Insert

        /// <summary>
        /// 
        /// </summary>
        event AccessEventHandler CanInsert;

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Inserting;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        TEntity Insert(TEntity entity);

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Inserted;

        #endregion

        #region Select
        
        /// <summary>
        /// 
        /// </summary>
        event AccessEventHandler CanRead;

        /// <summary>
        /// 
        /// </summary>
        event FilterEventHandler<TEntity> Filter;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        TEntity GetByKey(object keyValue);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        TEntity GetByKeys(params object[] keyValues);

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> Get();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        IEnumerable<TEntity> Get(Func<TEntity, bool> filter);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        IEnumerable<TEntity> Get(Func<IEnumerable<TEntity>, IOrderedEnumerable<TEntity>> order);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        IEnumerable<TEntity> Get(Func<TEntity, bool> filter, Func<IEnumerable<TEntity>, IOrderedEnumerable<TEntity>> order);

        #endregion

        #region Update

        /// <summary>
        /// 
        /// </summary>
        event AccessEventHandler CanUpdate;

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Updating;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        TEntity Update(TEntity entity);

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Updated;

        #endregion
        
        #region Delete

        /// <summary>
        /// 
        /// </summary>
        event AccessEventHandler CanDelete;

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Deleting;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        TEntity Delete(object keyValue);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        TEntity Delete(params object[] keyValues);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        TEntity Delete(TEntity entity);

        /// <summary>
        /// 
        /// </summary>
        event ActionEventHandler<TEntity> Deleted;

        #endregion
    }
}
